package org.tlang.type;

import org.tlang.ast.AST;
import org.tlang.context.TypeTable;
import org.tlang.exception.EvalException;
import org.tlang.exception.TypeException;
import org.tlang.keywords.KeyWords;

public abstract class Type {

    public abstract boolean isTypeOf(Type type);

    public boolean isSubTypeOf(Type type, TypeTable typeTable) {
        return isTypeOf(type);
    }

    public boolean isPrimitiveType() {
        return false;
    }

    public boolean isFuncType() {
        return false;
    }

    public boolean isClassType() {
        return false;
    }

    public boolean isArrayType() {
        return false;
    }

    @Override
    public String toString() {
        return KeyWords.TYPE_VOID;
    }

    public void assertSubTypeOf(Type type, TypeTable typeTable, AST ast) throws TypeException {
        if (!isSubTypeOf(type, typeTable)) {
            throw new TypeException("type not match: cannot cast from " + this + " to " + type, ast);
        }
    }

    public void assertTypeOf(Type type, AST ast) throws TypeException {
        if (!isTypeOf(type)) {
            throw new TypeException("type not match of " + this + " with " + type, ast);
        }
    }

    public static boolean isPreDefinedType(String name) {
        switch (name) {
            case KeyWords.TYPE_INT:
            case KeyWords.TYPE_BOOL:
            case KeyWords.TYPE_STR:
            case KeyWords.TYPE_VOID:
            case KeyWords.TYPE_FLOAT:
                return true;
            default:
                return false;
        }
    }

    public static Type tranStrToType(String name, AST ast) {
        Type type;
        switch (name) {
            case KeyWords.TYPE_INT:
                type = IntType.INT_TYPE;
                break;
            case KeyWords.TYPE_BOOL:
                type = BoolType.BOOL_TYPE;
                break;
            case KeyWords.TYPE_STR:
                type = StrType.STR_TYPE;
                break;
            case KeyWords.TYPE_VOID:
                type = VoidType.VOID_TYPE;
                break;
            case KeyWords.TYPE_FLOAT:
                type = FloatType.FLOAT_TYPE;
                break;
            default:
                throw new EvalException("not support type: " + name, ast);
        }
        return type;
    }
}